from typing import Tuple, Optional
import ipaddress
from urllib import parse as urllib_parse

from django.utils.translation import gettext as _

from core import errors
from apps.app_auth_provider.models import AllowedRedirect


def is_domain_match(host: str, pattern: str) -> bool:
    """
    判断 host 是否匹配 pattern（支持 *.example.com 这种通配符）
    """
    # 精确匹配
    if host.startswith('.'):
        return False

    if host == pattern:
        return True

    # 通配符匹配 *.example.com -> a.example.com, a.b.example.com ...
    if pattern.startswith("*."):
        # 分割主域部分
        pattern_domain = pattern[2:]
        pattern_parts = pattern_domain.split(".")
        host_parts = host.split(".")

        # host域名层级 要比 主域名层级多
        domaim_len = len(pattern_parts)
        if len(host_parts) <= domaim_len:
            return False

        # 主域是否一致
        return ".".join(host_parts[-domaim_len:]) == pattern_domain

    return False


def is_ip_match(ip: str, cidr: str) -> bool:
    """
    判断 ip 是否属于 cidr 表示的网络范围
    cidr: 192.168.1.0/24
    """
    try:
        ip_obj = ipaddress.ip_address(ip)
        network = ipaddress.ip_network(cidr, strict=False)
        return ip_obj in network
    except ValueError:
        return False


def is_host_match(host: str, pattern: str) -> bool:
    """
    自动判断 host 是否匹配 pattern。
    支持：
      - 域名：*.example.com
      - IP地址：192.168.1.0/24
    """
    # 如果 pattern 是 CIDR 格式，则当作 IP 处理
    if "/" in pattern:
        return is_ip_match(host, pattern)

    # 否则当作域名处理
    return is_domain_match(host, pattern)


class AllowedRedirectManager:
    @staticmethod
    def check_allowed_redirect_uri(uri: str) -> Tuple[bool, Optional[errors.Error]]:
        try:
            parse_obj = urllib_parse.urlparse(uri)
        except ValueError as exc:
            return False, errors.InvalidArgument(message=_('不是一个有效的url。') + str(exc))

        if not parse_obj.scheme or not parse_obj.netloc:
            return False, errors.InvalidArgument(message=_('不是一个有效的url。'))

        host = parse_obj.hostname
        if AllowedRedirect.objects.filter(
            pattern=host,
            pattern_type=AllowedRedirect.PatternType.EXACT.value,
            is_active=True
        ).exists():
            return True, None

        # 通配符格式匹配
        objs = AllowedRedirect.objects.filter(
            pattern_type=AllowedRedirect.PatternType.WILDCARD.value,
            is_active=True
        ).all()
        for obj in objs:
            try:
                ok = is_host_match(host=host, pattern=obj.pattern)
                if ok:
                    return True, None
            except Exception:
                continue

        return False, errors.AccessDenied(message=_('回调地址没有认证权限，请联系工作人员添加白名单。'))

    @staticmethod
    def create_allowed_redirect(
            name: str,
            pattern: str,
            pattern_type: str = AllowedRedirect.PatternType.EXACT.value,
            is_active: bool = True,
            description: str = '',
            create_user: str = ''
    ) -> AllowedRedirect:
        obj = AllowedRedirect(
            name=name,
            pattern=pattern,
            pattern_type=pattern_type,
            is_active=is_active,
            description=description,
            create_user=create_user
        )
        obj.save(force_insert=True)
        return obj
